package NG::Sys::Spec::BlockerClient;
use strict;
use warnings;

use NG::Sys::Cfg;
use NG::Sys::Sock qw(UnixConnect InetConnect);

sub new {
    my $class = shift;
	my $app = shift;
	my $config = shift;
	my $cfg = config($config)->{blocker} || die "no config for blocker '$config'";
    my $self = bless {
		yes => $cfg->{yes},
		proc => $app->script,
		logger => $app->logger,
		has => {},
		}, $class;
	if($cfg->{unix}){
		$self->{connector} = \&UnixConnect;
		$self->{carg} = [$app->{cfg}{path}{var}."/".$cfg->{unix}{path},1];
	}elsif($cfg->{inet}){
		$self->{connector} = \&InetConnect;
		$self->{carg} = [@{$cfg->{inet}}{'peer','port'},1];
	}else{
		die "cannot create connector for '$config'";
	}
    return $self;
}
sub logger {
	my $self = shift;
	return $self->{logger};
}
sub _send_message {
	my $self = shift;
	my $cmd = shift;
	my $key = shift;
	my $to_send = $cmd." ".$key." ".$$." ".$self->{proc}.chr(0);
	my $sock;
	for(;;) {
		unless($sock = $self->{sock}){
			my $try = 0;
			until($sock = $self->{sock} = $self->{connector}->(@{$self->{carg}})){
				if(++$try > 10){
					die "cannot connect to $self->{path}\n";
				}
				sleep 1;
			}
		}
		unless($sock->opened && $sock->connected){
			delete $self->{sock};
			next;
		}
		unless($sock->send($to_send)){
			delete $self->{sock};
			next;
		}
		my $buf;
		$sock->recv($buf,1024);
		unless($buf){
			delete $self->{sock};
			next;
		}
		if($key){
			return $buf eq $self->{yes};
		}else{
			return $buf;
		}
	}
}
sub has {
	my ($self,$key) = @_;
	return $self->{has}{$key};
}
sub get {
	my ($self,$key) = @_;
	if(my $res = $self->{has}{$key}){
		return $res;
	}
	$self->{has}{$key} = _send_message($self,"get",$key);
}
sub try {
	my ($self,$key) = @_;
	if(my $res = $self->{has}{$key}){
		return $res;
	}
	$self->{has}{$key} = _send_message($self,"try",$key);
}
sub weak {
	my ($self,$key) = @_;
	if(my $res = $self->{has}{$key}){
		return $res;
	}
	$self->{has}{$key} = _send_message($self,"weak",$key);
}
sub free {
	my ($self,$key) = @_;
	unless(delete $self->{has}{$key}){
		return undef;
	}else{
		return _send_message($self,"free",$key);
	}
}
sub stat {
	my ($self) = @_;
	return _send_message($self,"stat","");
}

1;
